use crate::ast::*;
use crate::ast::types::FunctionType as AstFunctionType;
use crate::error::{CompilerError, Result};
use inkwell::{
    types::{
        BasicMetadataTypeEnum, BasicType, BasicTypeEnum, FunctionType as LLVMFunctionType,
        PointerType,
    },
    values::{BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue, PointerValue},
    AddressSpace,
};

use super::LLVMBackend;

impl<'ctx> LLVMBackend<'ctx> {
    fn find_struct_by_field(&self, field_name: &str) -> Option<&StructDecl> {
        for (_, struct_decl) in &self.struct_declarations {
            if struct_decl
                .fields
                .iter()
                .any(|field| field.name == field_name)
            {
                return Some(struct_decl);
            }
        }
        None
    }

    /// Resolve struct declaration from a concrete type, walking through wrappers like references.
    pub(super) fn resolve_struct_decl_from_type(&self, ty: &Type) -> Option<&StructDecl> {
        match ty {
            Type::Struct(struct_type) => {
                if self.trait_declarations.contains_key(&struct_type.name) {
                    None
                } else {
                    self.struct_declarations.get(&struct_type.name)
                }
            }
            Type::Reference(ref_type) => self.resolve_struct_decl_from_type(&ref_type.referenced_type),
            Type::Rc(rc_type) => self.resolve_struct_decl_from_type(&rc_type.inner_type),
            Type::Weak(weak_type) => self.resolve_struct_decl_from_type(&weak_type.inner_type),
            Type::Optional(optional_type) => self.resolve_struct_decl_from_type(&optional_type.inner_type),
            Type::Option(option_type) => self.resolve_struct_decl_from_type(&option_type.some_type),
            Type::Error(error_type) => self.resolve_struct_decl_from_type(&error_type.inner_type),
            Type::Result(result_type) => self
                .resolve_struct_decl_from_type(&result_type.ok_type)
                .or_else(|| self.resolve_struct_decl_from_type(&result_type.err_type)),
            Type::Alias(alias_type) => self.struct_declarations.get(&alias_type.name),
            _ => None,
        }
    }

    /// Resolve the struct declaration for a specific field access expression.
    pub(super) fn resolve_struct_for_field_access(
        &self,
        object_expr: &Expression,
        field_name: &str,
    ) -> Option<&StructDecl> {
        // First, try to use the recorded variable type if this is a simple variable.
        if let Expression::Variable(var_name) = object_expr {
            if let Some(var_type) = self.variable_type_map.get(var_name) {
                if let Some(decl) = self.resolve_struct_decl_from_type(var_type) {
                    return Some(decl);
                }
            }
        }

        // Fall back to type inference on the expression tree (covers field access chains, etc.)
        if let Some(expr_type) = self.infer_expression_type(object_expr) {
            if let Some(decl) = self.resolve_struct_decl_from_type(&expr_type) {
                return Some(decl);
            }
        }

        // As a last resort, scan all structs by field name.
        self.find_struct_by_field(field_name)
    }

    /// Returns the trait name if the provided type denotes a trait
    pub fn trait_name_from_type(&self, ty: &Type) -> Option<String> {
        match ty {
            Type::Struct(struct_type) => {
                if self.trait_declarations.contains_key(&struct_type.name) {
                    Some(struct_type.name.clone())
                } else {
                    None
                }
            }
            Type::Generic(name) => {
                if self.trait_declarations.contains_key(name) {
                    Some(name.clone())
                } else {
                    None
                }
            }
            Type::Alias(alias_type) => {
                if self.trait_declarations.contains_key(&alias_type.name) {
                    Some(alias_type.name.clone())
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    /// Check whether a struct type matches the `{i8*, i8*}` layout used by trait handles.
    pub fn is_trait_handle_struct_type(
        &self,
        struct_type: inkwell::types::StructType<'ctx>,
    ) -> bool {
        if struct_type.count_fields() != 2 {
            return false;
        }
        let i8_ptr = self.context.i8_type().ptr_type(AddressSpace::default());
        struct_type
            .get_field_types()
            .iter()
            .all(|field| matches!(field, BasicTypeEnum::PointerType(ptr) if *ptr == i8_ptr))
    }

    /// Ensure an LLVM struct type exists for the specified trait object
    pub fn ensure_trait_object_type(
        &mut self,
        trait_name: &str,
    ) -> inkwell::types::StructType<'ctx> {
        if let Some(existing) = self.trait_object_types.get(trait_name) {
            return *existing;
        }

        let i8_ptr = self.context.i8_type().ptr_type(AddressSpace::default());
        let struct_type = self
            .context
            .struct_type(&[i8_ptr.into(), i8_ptr.into()], false);
        self.trait_object_types
            .insert(trait_name.to_string(), struct_type);
        struct_type
    }

    /// Ensure an LLVM struct type exists for Rc trait handles (rc_ptr + vtable_ptr).
    pub fn ensure_trait_rc_handle_type(
        &mut self,
        trait_name: &str,
    ) -> inkwell::types::StructType<'ctx> {
        if let Some(existing) = self.trait_rc_handle_types.get(trait_name) {
            return *existing;
        }

        let i8_ptr = self.context.i8_type().ptr_type(AddressSpace::default());
        // Field0: rc block pointer, Field1: vtable pointer
        let struct_type = self.context.struct_type(&[i8_ptr.into(), i8_ptr.into()], false);
        self.trait_rc_handle_types
            .insert(trait_name.to_string(), struct_type);
        struct_type
    }

    /// Ensure an LLVM struct type exists for Weak trait handles (weak_ptr + vtable_ptr).
    pub fn ensure_trait_weak_handle_type(
        &mut self,
        trait_name: &str,
    ) -> inkwell::types::StructType<'ctx> {
        if let Some(existing) = self.trait_weak_handle_types.get(trait_name) {
            return *existing;
        }

        let i8_ptr = self.context.i8_type().ptr_type(AddressSpace::default());
        let struct_type = self.context.struct_type(&[i8_ptr.into(), i8_ptr.into()], false);
        self.trait_weak_handle_types
            .insert(trait_name.to_string(), struct_type);
        struct_type
    }

    /// Retrieve the cached LLVM struct type for a trait object if available
    pub fn get_trait_object_type(
        &self,
        trait_name: &str,
    ) -> Option<inkwell::types::StructType<'ctx>> {
        self.trait_object_types.get(trait_name).copied()
    }

    /// Decompose an `Rc<Trait>` handle into its rc block pointer and cached vtable pointer.
    pub fn extract_trait_rc_components(
        &mut self,
        trait_name: &str,
        value: BasicValueEnum<'ctx>,
    ) -> Result<(PointerValue<'ctx>, PointerValue<'ctx>)> {
        let handle_type = self.ensure_trait_rc_handle_type(trait_name);
        let struct_value = match value {
            BasicValueEnum::StructValue(val) => val,
            BasicValueEnum::PointerValue(ptr) => self
                .builder
                .build_load(handle_type, ptr, "load_trait_rc_handle")?
                .into_struct_value(),
            _ => {
                return Err(CompilerError::internal(
                    "Trait Rc handle must be a struct value or pointer",
                ))
            }
        };

        let rc_ptr = self
            .builder
            .build_extract_value(struct_value, 0, "trait_rc_ptr")?
            .into_pointer_value();
        let vtable_ptr = self
            .builder
            .build_extract_value(struct_value, 1, "trait_rc_vtable")?
            .into_pointer_value();
        Ok((rc_ptr, vtable_ptr))
    }

    /// Build an `Rc<Trait>` handle struct from an rc block pointer and a trait vtable pointer.
    pub fn build_trait_rc_value(
        &mut self,
        trait_name: &str,
        rc_ptr: PointerValue<'ctx>,
        vtable_ptr: PointerValue<'ctx>,
    ) -> Result<BasicValueEnum<'ctx>> {
        let handle_type = self.ensure_trait_rc_handle_type(trait_name);
        let handle = handle_type.get_undef();
        let i8_ptr = self.context.i8_type().ptr_type(AddressSpace::default());
        let rc_ptr_cast = self
            .builder
            .build_bitcast(rc_ptr, i8_ptr, "trait_rc_ptr_cast")?
            .into_pointer_value();
        let vtable_cast = self
            .builder
            .build_bitcast(vtable_ptr, i8_ptr, "trait_rc_vtable_cast")?
            .into_pointer_value();
        let handle = self
            .builder
            .build_insert_value(handle, rc_ptr_cast, 0, "trait_rc_insert_ptr")?
            .into_struct_value();
        let handle = self
            .builder
            .build_insert_value(handle, vtable_cast, 1, "trait_rc_insert_vtable")?
            .into_struct_value();
        Ok(handle.into())
    }

    /// Decompose a `Weak<Trait>` handle into its weak pointer and cached vtable pointer.
    pub fn extract_trait_weak_components(
        &mut self,
        trait_name: &str,
        value: BasicValueEnum<'ctx>,
    ) -> Result<(PointerValue<'ctx>, PointerValue<'ctx>)> {
        let handle_type = self.ensure_trait_weak_handle_type(trait_name);
        let struct_value = match value {
            BasicValueEnum::StructValue(val) => val,
            BasicValueEnum::PointerValue(ptr) => self
                .builder
                .build_load(handle_type, ptr, "load_trait_weak_handle")?
                .into_struct_value(),
            _ => {
                return Err(CompilerError::internal(
                    "Trait Weak handle must be a struct value or pointer",
                ))
            }
        };

        let weak_ptr = self
            .builder
            .build_extract_value(struct_value, 0, "trait_weak_ptr")?
            .into_pointer_value();
        let vtable_ptr = self
            .builder
            .build_extract_value(struct_value, 1, "trait_weak_vtable")?
            .into_pointer_value();
        Ok((weak_ptr, vtable_ptr))
    }

    /// Build a `Weak<Trait>` handle from a weak pointer and a trait vtable pointer.
    pub fn build_trait_weak_value(
        &mut self,
        trait_name: &str,
        weak_ptr: PointerValue<'ctx>,
        vtable_ptr: PointerValue<'ctx>,
    ) -> Result<BasicValueEnum<'ctx>> {
        let handle_type = self.ensure_trait_weak_handle_type(trait_name);
        let handle = handle_type.get_undef();
        let i8_ptr = self.context.i8_type().ptr_type(AddressSpace::default());
        let weak_cast = self
            .builder
            .build_bitcast(weak_ptr, i8_ptr, "trait_weak_ptr_cast")?
            .into_pointer_value();
        let vtable_cast = self
            .builder
            .build_bitcast(vtable_ptr, i8_ptr, "trait_weak_vtable_cast")?
            .into_pointer_value();
        let handle = self
            .builder
            .build_insert_value(handle, weak_cast, 0, "trait_weak_insert_ptr")?
            .into_struct_value();
        let handle = self
            .builder
            .build_insert_value(handle, vtable_cast, 1, "trait_weak_insert_vtable")?
            .into_struct_value();
        Ok(handle.into())
    }

    /// Ensure an LLVM struct type exists for a trait's vtable layout.
    pub fn ensure_trait_vtable_type(
        &mut self,
        trait_name: &str,
        method_count: usize,
    ) -> inkwell::types::StructType<'ctx> {
        if let Some(existing) = self.trait_vtable_types.get(trait_name) {
            return *existing;
        }

        let i8_ptr = self.context.i8_type().ptr_type(AddressSpace::default());
        let count = method_count.max(1);
        let fields: Vec<_> = (0..count).map(|_| i8_ptr.into()).collect();
        let ty = self.context.struct_type(&fields, false);
        self.trait_vtable_types
            .insert(trait_name.to_string(), ty);
        ty
    }

    /// Extract a concrete type name if possible (struct, alias, generic).
    pub fn extract_type_name(&self, ty: &Type) -> Option<String> {
        match ty {
            Type::Struct(struct_type) => Some(struct_type.name.clone()),
            Type::Alias(alias_type) => Some(alias_type.name.clone()),
            Type::Generic(name) => Some(name.clone()),
            _ => None,
        }
    }

    fn trait_impl_key(trait_name: &str, type_name: &str) -> (String, String) {
        (trait_name.to_string(), type_name.to_string())
    }

    pub(super) fn trait_method_llvm_type(
        &mut self,
        method: &TraitMethod,
    ) -> Result<LLVMFunctionType<'ctx>> {
        let i8_ptr = self.context.i8_type().ptr_type(AddressSpace::default());
        let mut param_types: Vec<BasicMetadataTypeEnum> = vec![i8_ptr.into()];

        let param_offset = if method
            .parameters
            .first()
            .map(|p| p.name.as_str() == "self")
            .unwrap_or(false)
        {
            1
        } else {
            0
        };

        for param in method.parameters.iter().skip(param_offset) {
            let llvm_type = self.nrc_type_to_llvm_type(&Some(param.param_type.clone()))?;
            param_types.push(llvm_type.into());
        }

        let fn_type = if let Some(ret_type) = &method.return_type {
            let ret_llvm_type = self.nrc_type_to_llvm_type(&Some(ret_type.clone()))?;
            ret_llvm_type.fn_type(&param_types, false)
        } else {
            self.context.void_type().fn_type(&param_types, false)
        };

        Ok(fn_type)
    }

    fn get_or_create_trait_method_shim(
        &mut self,
        trait_name: &str,
        type_name: &str,
        trait_method: &TraitMethod,
        impl_method: &FunctionDecl,
    ) -> Result<FunctionValue<'ctx>> {
        let key = (
            trait_name.to_string(),
            type_name.to_string(),
            trait_method.name.clone(),
        );
        if let Some(existing) = self.trait_method_shims.get(&key) {
            return Ok(*existing);
        }

        // Resolve implementation function
        let mut method_copy = impl_method.clone();
        method_copy.name = format!("{}.{}", type_name, impl_method.name);
        let symbol_name = self.function_symbol_name(&method_copy);
        let target_fn = *self
            .function_map
            .get(&symbol_name)
            .ok_or_else(|| CompilerError::internal("Trait implementation function not declared"))?;

        let fn_type = target_fn.get_type();
        let shim_name = format!(
            "__nrc_trait_shim_{}_{}_{}",
            trait_name, type_name, trait_method.name
        );
        let shim_fn = self.module.add_function(&shim_name, fn_type, None);
        let builder = self.context.create_builder();
        let entry = self.context.append_basic_block(shim_fn, "entry");
        builder.position_at_end(entry);

        // Prepare receiver cast
        let data_param = shim_fn.get_first_param().unwrap().into_pointer_value();
        let struct_type = self.nrc_type_to_llvm_type(&Some(Type::Struct(StructType {
            name: type_name.to_string(),
            type_args: vec![],
            location: trait_method.location,
        })))?;
        let struct_ptr_type = struct_type.ptr_type(AddressSpace::default());
        let typed_self = builder
            .build_bitcast(data_param, struct_ptr_type, "trait_self")?
            .into_pointer_value();

        let mut call_args: Vec<BasicMetadataValueEnum> = vec![typed_self.into()];
        for param in shim_fn.get_params().iter().skip(1) {
            call_args.push((*param).into());
        }

        let call_site = builder.build_call(target_fn, &call_args, "trait_impl_call")?;
        if target_fn.get_type().get_return_type().is_none() {
            builder.build_return(None)?;
        } else {
            let ret_val = call_site.try_as_basic_value().left().unwrap();
            builder.build_return(Some(&ret_val))?;
        }

        self.trait_method_shims.insert(key, shim_fn);
        self.function_map.insert(shim_name, shim_fn);
        Ok(shim_fn)
    }

    /// Fetch (or build) the global vtable pointer for a concrete type implementing a trait.
    pub fn get_or_create_trait_vtable_ptr(
        &mut self,
        trait_name: &str,
        type_name: &str,
    ) -> Result<PointerValue<'ctx>> {
        if let Some(ptr) = self
            .trait_vtable_globals
            .get(&(trait_name.to_string(), type_name.to_string()))
        {
            return Ok(*ptr);
        }

        let trait_decl = self
            .trait_declarations
            .get(trait_name)
            .cloned()
            .ok_or_else(|| CompilerError::internal(&format!("Unknown trait '{}'", trait_name)))?;
        let trait_impl = self
            .trait_impls
            .get(&Self::trait_impl_key(trait_name, type_name))
            .cloned()
            .ok_or_else(|| {
                CompilerError::internal(&format!(
                    "Type '{}' does not implement trait '{}'",
                    type_name, trait_name
                ))
            })?;

        let i8_ptr = self.context.i8_type().ptr_type(AddressSpace::default());
        let mut values = Vec::new();

        for method in &trait_decl.methods {
            let impl_method = trait_impl
                .methods
                .iter()
                .find(|m| m.name == method.name)
                .ok_or_else(|| {
                    CompilerError::internal(&format!(
                        "Trait '{}' method '{}' not implemented for '{}'",
                        trait_name, method.name, type_name
                    ))
                })?;

            let shim = self.get_or_create_trait_method_shim(
                trait_name,
                type_name,
                method,
                impl_method,
            )?;
            let fn_ptr = shim.as_global_value().as_pointer_value();
            let cast_ptr = fn_ptr.const_cast(i8_ptr);
            values.push(cast_ptr.as_basic_value_enum());
        }

        if values.is_empty() {
            values.push(i8_ptr.const_null().as_basic_value_enum());
        }

        let vtable_type =
            self.ensure_trait_vtable_type(trait_name, trait_decl.methods.len());
        let initializer = vtable_type.const_named_struct(&values);
        let global_name = format!("__nrc_vtable_{}_{}", trait_name, type_name);
        let global = self
            .module
            .add_global(vtable_type, Some(AddressSpace::default()), &global_name);
        global.set_constant(true);
        global.set_initializer(&initializer);
        let ptr = global.as_pointer_value();
        self.trait_vtable_globals
            .insert((trait_name.to_string(), type_name.to_string()), ptr);
        Ok(ptr)
    }

    fn convert_reference_to_trait_object(
        &mut self,
        value: BasicValueEnum<'ctx>,
        concrete_type: &Type,
        trait_name: &str,
    ) -> Result<BasicValueEnum<'ctx>> {
        let ptr_value = match value {
            BasicValueEnum::PointerValue(ptr) => ptr,
            _ => {
                return Err(CompilerError::internal(
                    "Trait reference conversion expects pointer value",
                ))
            }
        };

        let type_name = self.extract_type_name(concrete_type).ok_or_else(|| {
            CompilerError::internal("Cannot determine concrete type name for trait object")
        })?;

        if !self
            .trait_impls
            .contains_key(&Self::trait_impl_key(trait_name, &type_name))
        {
            return Err(CompilerError::internal(&format!(
                "Type '{}' does not implement trait '{}'",
                type_name, trait_name
            )));
        }

        let trait_struct = self.ensure_trait_object_type(trait_name);
        let alloca = self.builder.build_alloca(trait_struct, "trait_object")?;
        let i8_ptr = self.context.i8_type().ptr_type(AddressSpace::default());

        let data_ptr = self
            .builder
            .build_bitcast(ptr_value, i8_ptr, "trait_data_ptr")?
            .into_pointer_value();
        let data_field = self
            .builder
            .build_struct_gep(trait_struct, alloca, 0, "trait_data_field")?;
        self.builder.build_store(data_field, data_ptr)?;

        let vtable_ptr = self.get_or_create_trait_vtable_ptr(trait_name, &type_name)?;
        let vtable_ptr_i8 = self
            .builder
            .build_bitcast(vtable_ptr, i8_ptr, "trait_vtable_ptr")?
            .into_pointer_value();
        let vtable_field = self
            .builder
            .build_struct_gep(trait_struct, alloca, 1, "trait_vtable_field")?;
        self.builder.build_store(vtable_field, vtable_ptr_i8)?;

        Ok(alloca.into())
    }

    fn convert_rc_to_trait_object(
        &mut self,
        value: BasicValueEnum<'ctx>,
        concrete_type: &Type,
        trait_name: &str,
    ) -> Result<BasicValueEnum<'ctx>> {
        let rc_ptr = match value {
            BasicValueEnum::PointerValue(ptr) => ptr,
            _ => {
                return Err(CompilerError::internal(
                    "Rc conversion expects rc block pointer",
                ))
            }
        };

        let type_name = self.extract_type_name(concrete_type).ok_or_else(|| {
            CompilerError::internal("Cannot determine concrete type name for Rc trait object")
        })?;

        if !self
            .trait_impls
            .contains_key(&Self::trait_impl_key(trait_name, &type_name))
        {
            return Err(CompilerError::internal(&format!(
                "Type '{}' does not implement trait '{}'",
                type_name, trait_name
            )));
        }

        let vtable_ptr = self.get_or_create_trait_vtable_ptr(trait_name, &type_name)?;
        self.build_trait_rc_value(trait_name, rc_ptr, vtable_ptr)
    }

    fn convert_weak_to_trait_object(
        &mut self,
        value: BasicValueEnum<'ctx>,
        concrete_type: &Type,
        trait_name: &str,
    ) -> Result<BasicValueEnum<'ctx>> {
        let weak_ptr = match value {
            BasicValueEnum::PointerValue(ptr) => ptr,
            _ => {
                return Err(CompilerError::internal(
                    "Weak conversion expects rc block pointer",
                ))
            }
        };

        let type_name = self.extract_type_name(concrete_type).ok_or_else(|| {
            CompilerError::internal("Cannot determine concrete type name for Weak trait object")
        })?;

        if !self
            .trait_impls
            .contains_key(&Self::trait_impl_key(trait_name, &type_name))
        {
            return Err(CompilerError::internal(&format!(
                "Type '{}' does not implement trait '{}'",
                type_name, trait_name
            )));
        }

        let vtable_ptr = self.get_or_create_trait_vtable_ptr(trait_name, &type_name)?;
        self.build_trait_weak_value(trait_name, weak_ptr, vtable_ptr)
    }

    /// Extract the rc block pointer from either a thin `Rc<T>` pointer or a trait handle struct.
    pub fn rc_block_pointer_from_value(
        &mut self,
        value: BasicValueEnum<'ctx>,
        rc_type: &types::RcType,
    ) -> Result<PointerValue<'ctx>> {
        if let Some(trait_name) = self.trait_name_from_type(&rc_type.inner_type) {
            let (rc_ptr, _) = self.extract_trait_rc_components(&trait_name, value)?;
            Ok(rc_ptr)
        } else if let BasicValueEnum::PointerValue(ptr) = value {
            Ok(ptr)
        } else {
            Err(CompilerError::internal(
                "Rc value should be a pointer to rc block",
            ))
        }
    }

    /// Extract the weak block pointer from either a thin `Weak<T>` pointer or a trait handle struct.
    pub fn weak_block_pointer_from_value(
        &mut self,
        value: BasicValueEnum<'ctx>,
        weak_type: &types::WeakType,
    ) -> Result<PointerValue<'ctx>> {
        if let Some(trait_name) = self.trait_name_from_type(&weak_type.inner_type) {
            let (weak_ptr, _) = self.extract_trait_weak_components(&trait_name, value)?;
            Ok(weak_ptr)
        } else if let BasicValueEnum::PointerValue(ptr) = value {
            Ok(ptr)
        } else {
            Err(CompilerError::internal(
                "Weak value should be a pointer to rc block",
            ))
        }
    }

    /// Attempt to coerce a generated value into the expected target type (used for trait refs).
    pub fn coerce_value_to_type(
        &mut self,
        value: BasicValueEnum<'ctx>,
        value_type: Option<&Type>,
        target_type: &Type,
    ) -> Result<BasicValueEnum<'ctx>> {
        if let Type::Reference(target_ref) = target_type {
            if let Some(trait_name) = self.trait_name_from_type(&target_ref.referenced_type) {
                if let Some(actual_type) = value_type {
                    match actual_type {
                        Type::Reference(actual_ref) => {
                            if let Some(current_trait) =
                                self.trait_name_from_type(&actual_ref.referenced_type)
                            {
                                if current_trait == trait_name {
                                    // Already &Trait
                                    return Ok(value);
                                }
                            }
                            return self.convert_reference_to_trait_object(
                                value,
                                &actual_ref.referenced_type,
                                &trait_name,
                            );
                        }
                        // Handle cases where the inferred type is a plain
                        // type name (Generic/Struct/Alias) pointing to the
                        // concrete implementation type.
                        _ => {
                            if let Some(current_trait) = self.trait_name_from_type(actual_type) {
                                if current_trait == trait_name {
                                    return Ok(value);
                                }
                            }
                            return self
                                .convert_reference_to_trait_object(value, actual_type, &trait_name);
                        }
                    }
                }
            }
        }

        if let Type::Rc(target_rc) = target_type {
            if let Some(trait_name) = self.trait_name_from_type(&target_rc.inner_type) {
                if let Some(actual_type) = value_type {
                    if let Type::Rc(actual_rc) = actual_type {
                        if let Some(current_trait) =
                            self.trait_name_from_type(&actual_rc.inner_type)
                        {
                            if current_trait == trait_name {
                                return Ok(value);
                            } else {
                                return Err(CompilerError::internal(
                                    "Cannot convert Rc<trait> to different trait",
                                ));
                            }
                        }
                        return self.convert_rc_to_trait_object(
                            value,
                            &actual_rc.inner_type,
                            &trait_name,
                        );
                    }
                } else {
                    // No type information available; assume value is already in the desired form.
                    return Ok(value);
                }
            }
        }

        if let Type::Weak(target_weak) = target_type {
            if let Some(trait_name) = self.trait_name_from_type(&target_weak.inner_type) {
                if let Some(actual_type) = value_type {
                    if let Type::Weak(actual_weak) = actual_type {
                        if let Some(current_trait) =
                            self.trait_name_from_type(&actual_weak.inner_type)
                        {
                            if current_trait == trait_name {
                                return Ok(value);
                            } else {
                                return Err(CompilerError::internal(
                                    "Cannot convert Weak<trait> to different trait",
                                ));
                            }
                        }
                        return self.convert_weak_to_trait_object(
                            value,
                            &actual_weak.inner_type,
                            &trait_name,
                        );
                    }
                } else {
                    // No type information available; assume value is already in the desired form.
                    return Ok(value);
                }
            }
        }
        Ok(value)
    }

    /// Convert a type name string to BasicType enum
    fn name_to_basic_type(name: &str) -> Option<types::BasicType> {
        match name {
            "int" => Some(types::BasicType::Int),
            "int8" => Some(types::BasicType::Int8),
            "int16" => Some(types::BasicType::Int16),
            "int32" => Some(types::BasicType::Int32),
            "int64" => Some(types::BasicType::Int64),
            "uint" => Some(types::BasicType::Uint),
            "uint8" => Some(types::BasicType::Uint8),
            "uint16" => Some(types::BasicType::Uint16),
            "uint32" => Some(types::BasicType::Uint32),
            "uint64" => Some(types::BasicType::Uint64),
            "float32" => Some(types::BasicType::Float32),
            "float64" => Some(types::BasicType::Float64),
            "bool" => Some(types::BasicType::Bool),
            "String" => Some(types::BasicType::String),
            "char" => Some(types::BasicType::Char),
            "rune" => Some(types::BasicType::Rune),
            "any" => Some(types::BasicType::Any),
            "void" => Some(types::BasicType::Void),
            _ => None,
        }
    }

    pub(super) fn closure_code_pointer_type(
        &self,
        function_type: &AstFunctionType,
    ) -> Result<PointerType<'ctx>> {
        let env_ptr_type = self.context.i8_type().ptr_type(AddressSpace::default());
        let mut param_types: Vec<BasicMetadataTypeEnum> =
            Vec::with_capacity(function_type.parameter_types.len() + 1);
        param_types.push(env_ptr_type.into());

        for param_type in &function_type.parameter_types {
            let llvm_type = self.nrc_type_to_llvm_type(&Some(param_type.clone()))?;
            param_types.push(llvm_type.into());
        }

        let fn_type = if let Some(ret_type) = &function_type.return_type {
            let llvm_ret = self.nrc_type_to_llvm_type(&Some(*ret_type.clone()))?;
            llvm_ret.fn_type(&param_types, function_type.variadic)
        } else {
            self.context
                .void_type()
                .fn_type(&param_types, function_type.variadic)
        };

        Ok(fn_type.ptr_type(AddressSpace::default()))
    }

    /// Convert NRC type to LLVM type
    pub(super) fn nrc_type_to_llvm_type(
        &self,
        nrc_type: &Option<Type>,
    ) -> Result<BasicTypeEnum<'ctx>> {
        match nrc_type {
            Some(Type::Basic(basic_type)) => match basic_type {
                types::BasicType::Int => Ok(self.context.i64_type().into()),
                types::BasicType::Int8 => Ok(self.context.i8_type().into()),
                types::BasicType::Int16 => Ok(self.context.i16_type().into()),
                types::BasicType::Int32 => Ok(self.context.i32_type().into()),
                types::BasicType::Int64 => Ok(self.context.i64_type().into()),
                types::BasicType::Uint => Ok(self.context.i64_type().into()),
                types::BasicType::Uint8 => Ok(self.context.i8_type().into()),
                types::BasicType::Uint16 => Ok(self.context.i16_type().into()),
                types::BasicType::Uint32 => Ok(self.context.i32_type().into()),
                types::BasicType::Uint64 => Ok(self.context.i64_type().into()),
                types::BasicType::Float32 => Ok(self.context.f32_type().into()),
                types::BasicType::Float64 => Ok(self.context.f64_type().into()),
                types::BasicType::String => Ok(self
                    .context
                    .i8_type()
                    .ptr_type(AddressSpace::default())
                    .into()),
                types::BasicType::Bool => Ok(self.context.bool_type().into()),
                types::BasicType::Char => Ok(self.context.i8_type().into()),
                types::BasicType::Rune => Ok(self.context.i32_type().into()),
                _ => Err(CompilerError::internal(&format!(
                    "Unsupported basic type: {:?}",
                    basic_type
                ))),
            },
            Some(Type::Reference(reference_type)) => {
                if let Some(trait_name) =
                    self.trait_name_from_type(&reference_type.referenced_type)
                {
                    if let Some(object_type) = self.trait_object_types.get(&trait_name) {
                        return Ok(
                            object_type.ptr_type(AddressSpace::default()).into()
                        );
                    }
                }
                // Convert reference type: &T -> T* (same as pointer for now)
                let referenced_type =
                    self.nrc_type_to_llvm_type(&Some(*reference_type.referenced_type.clone()))?;
                Ok(referenced_type.ptr_type(AddressSpace::default()).into())
            }
            Some(Type::Rc(rc_type)) => {
                if let Some(trait_name) = self.trait_name_from_type(&rc_type.inner_type) {
                    if let Some(handle_type) = self.trait_rc_handle_types.get(&trait_name) {
                        Ok((*handle_type).into())
                    } else {
                        Err(CompilerError::internal(&format!(
                            "Trait Rc handle type '{}' not initialized",
                            trait_name
                        )))
                    }
                } else {
                    // Convert Rc<T> to T* (reference counted pointer)
                    let inner_type =
                        self.nrc_type_to_llvm_type(&Some(*rc_type.inner_type.clone()))?;
                    Ok(inner_type.ptr_type(AddressSpace::default()).into())
                }
            }
            Some(Type::Weak(weak_type)) => {
                if let Some(trait_name) = self.trait_name_from_type(&weak_type.inner_type) {
                    if let Some(handle_type) = self.trait_weak_handle_types.get(&trait_name) {
                        Ok((*handle_type).into())
                    } else {
                        Err(CompilerError::internal(&format!(
                            "Trait Weak handle type '{}' not initialized",
                            trait_name
                        )))
                    }
                } else {
                    let inner_type =
                        self.nrc_type_to_llvm_type(&Some(*weak_type.inner_type.clone()))?;
                    Ok(inner_type.ptr_type(AddressSpace::default()).into())
                }
            }
            Some(Type::Generic(name)) => {
                // First check if this is a basic type name (string, bool, int32, etc.)
                if let Some(basic_type) = Self::name_to_basic_type(name) {
                    // Convert basic type to LLVM type recursively
                    return self.nrc_type_to_llvm_type(&Some(Type::Basic(basic_type)));
                }

                // For Go-style struct types that are parsed as Generic, look up the actual struct declaration
                if let Some(struct_decl) = self.struct_declarations.get(name) {
                    // Generate LLVM types for each field
                    let mut field_types = Vec::new();
                    for field in &struct_decl.fields {
                        let field_llvm_type =
                            self.nrc_type_to_llvm_type(&Some(field.field_type.clone()))?;
                        field_types.push(field_llvm_type.into());
                    }

                    let llvm_struct_type = self.context.struct_type(&field_types, false);
                    Ok(llvm_struct_type.into())
                } else if self.enum_declarations.contains_key(name) {
                    // This is an enum type, generate tagged union
                    self.get_enum_llvm_type(name)
                } else if let Some(trait_object) = self.trait_object_types.get(name) {
                    Ok((*trait_object).into())
                } else if self.trait_declarations.contains_key(name) {
                    Err(CompilerError::internal(&format!(
                        "Trait '{}' object type not initialized",
                        name
                    )))
                } else {
                    // Check if this might be a basic type that wasn't parsed correctly
                    // This can happen if 'string' is parsed as Generic instead of Basic
                    if let Some(basic_type) = Self::name_to_basic_type(name) {
                        return self.nrc_type_to_llvm_type(&Some(Type::Basic(basic_type)));
                    }
                    // Fallback: if neither struct nor enum declaration found, error
                    Err(CompilerError::internal(&format!(
                        "Type '{}' not found (neither struct nor enum)",
                        name
                    )))
                }
            }
            Some(Type::Struct(struct_type)) => {
                // Look up the actual struct declaration to get field information
                if let Some(struct_decl) = self.struct_declarations.get(&struct_type.name) {
                    // Generate LLVM types for each field
                    let mut field_types = Vec::new();
                    for field in &struct_decl.fields {
                        let field_llvm_type =
                            self.nrc_type_to_llvm_type(&Some(field.field_type.clone()))?;
                        field_types.push(field_llvm_type.into());
                    }

                    let llvm_struct_type = self.context.struct_type(&field_types, false);
                    Ok(llvm_struct_type.into())
                } else if self.enum_declarations.contains_key(&struct_type.name) {
                    // This is actually an enum type (parsed as Struct), generate tagged union
                    self.get_enum_llvm_type(&struct_type.name)
                } else if self.trait_declarations.contains_key(&struct_type.name) {
                    // Trait type - use the cached trait object representation
                    if let Some(trait_object) = self.trait_object_types.get(&struct_type.name) {
                        Ok((*trait_object).into())
                    } else {
                        Err(CompilerError::internal(&format!(
                            "Trait '{}' object type not initialized",
                            struct_type.name
                        )))
                    }
                } else {
                    // Fallback: if neither struct nor enum declaration found, error
                    Err(CompilerError::internal(&format!(
                        "Type '{}' not found (neither struct nor enum)",
                        struct_type.name
                    )))
                }
            }
            Some(Type::Tuple(tuple_type)) => {
                // Generate LLVM types for each tuple element
                let mut field_types = Vec::new();
                for element_type in &tuple_type.element_types {
                    let element_llvm_type =
                        self.nrc_type_to_llvm_type(&Some(element_type.clone()))?;
                    field_types.push(element_llvm_type);
                }

                // Create LLVM struct type to represent the tuple
                let llvm_tuple_type = self.context.struct_type(&field_types, false);
                Ok(llvm_tuple_type.into())
            }
            Some(Type::Vec(vector_type)) => {
                // Go-style slice: struct { ptr: *T, len: i64, cap: i64 }
                let element_type =
                    self.nrc_type_to_llvm_type(&Some(*vector_type.element_type.clone()))?;
                let ptr_type = element_type.ptr_type(AddressSpace::default());
                let len_type = self.context.i64_type();
                let cap_type = self.context.i64_type();

                let slice_struct_type = self
                    .context
                    .struct_type(&[ptr_type.into(), len_type.into(), cap_type.into()], false);
                Ok(slice_struct_type.into())
            }
            Some(Type::Map(map_type)) => {
                // Map: struct { keys: *K, values: *V, len: i64, cap: i64 }
                let key_type = self.nrc_type_to_llvm_type(&Some(*map_type.key_type.clone()))?;
                let value_type = self.nrc_type_to_llvm_type(&Some(*map_type.value_type.clone()))?;
                let keys_ptr_type = key_type.ptr_type(AddressSpace::default());
                let values_ptr_type = value_type.ptr_type(AddressSpace::default());
                let len_type = self.context.i64_type();
                let cap_type = self.context.i64_type();

                let map_struct_type = self.context.struct_type(
                    &[
                        keys_ptr_type.into(),
                        values_ptr_type.into(),
                        len_type.into(),
                        cap_type.into(),
                    ],
                    false,
                );
                Ok(map_struct_type.into())
            }
            Some(Type::Enum(enum_type)) => {
                // Enum: Generate tagged union representation
                // struct { i32 tag, [N x i8] data } where N is the size of largest variant
                self.get_enum_llvm_type(&enum_type.name)
            }
            Some(Type::Result(result_type)) => {
                // Result<T, E>: Generate tagged union representation
                // struct { i32 tag, [max(sizeof(T), sizeof(E)) x i8] data }
                // tag = 0 for Ok, tag = 1 for Err
                self.get_result_llvm_type(result_type)
            }
            Some(Type::Option(option_type)) => {
                // Option<T>: Generate tagged union representation
                // struct { i32 tag, [sizeof(T) x i8] data }
                // tag = 0 for Some, tag = 1 for None
                self.get_option_llvm_type(option_type)
            }
            Some(Type::Function(function_type)) => {
                let env_ptr_type = self.context.i8_type().ptr_type(AddressSpace::default());
                let fn_ptr_type = self.closure_code_pointer_type(function_type)?;
                let closure_struct = self
                    .context
                    .struct_type(&[fn_ptr_type.into(), env_ptr_type.into()], false);
                Ok(closure_struct.into())
            }
            None => Ok(self.context.i32_type().into()), // Default to int for void
            Some(ty) => Err(CompilerError::internal(&format!(
                "Unsupported type: {:?}",
                ty
            ))),
        }
    }
}
